package com.sunwayworld.common.hibernate;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;

import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.sunwayworld.common.utils.BeanUtils;

public class HibernateTemplateSpring extends HibernateTemplate {

	/**
	 * Create a new HibernateTemplate instance.
	 */
	public HibernateTemplateSpring() {
		super();
	}

	/**
	 * Create a new HibernateTemplate instance.
	 * 
	 * @param sessionFactory
	 *            SessionFactory to create Sessions
	 */
	public HibernateTemplateSpring(SessionFactory sessionFactory) {
		super(sessionFactory);
	}

	/**
	 * 覆盖 saveOrUpdate 方法实现 为null 的数据 不做保存
	 */
	public void saveOrUpdate(final Object entity) throws DataAccessException {
		execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				checkWriteOperationAllowed(session);
				ClassMetadata classMeta = session.getSessionFactory()
						.getClassMetadata(entity.getClass());
				Serializable pk = classMeta.getIdentifier(entity,
						EntityMode.POJO);
				Object entity_new = session.load(entity.getClass(), pk);
				BeanUtils.copyProperties(entity, entity_new);
				session.saveOrUpdate(entity_new);
				return null;
			}
		}, true);
	}

	/**
	 * 覆盖 saveOrUpdateAll 方法实现 为null 的数据 不做保存
	 */
	public void saveOrUpdateAll(final Collection entities)
			throws DataAccessException {
		execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				checkWriteOperationAllowed(session);
				ClassMetadata classMeta = null;
				for (Iterator it = entities.iterator(); it.hasNext();) {
					Object entity = it.next();
					if (classMeta == null) {
						classMeta = session.getSessionFactory()
								.getClassMetadata(entity.getClass());
					}

					Serializable pk = classMeta.getIdentifier(entity,
							EntityMode.POJO);
					Object entity_new = session.load(entity.getClass(), pk);
					BeanUtils.copyProperties(entity, entity_new);

					session.saveOrUpdate(entity);
				}
				return null;
			}
		}, true);
	}

	/**
	 * Create a new HibernateTemplate instance.
	 * 
	 * @param sessionFactory
	 *            SessionFactory to create Sessions
	 * @param allowCreate
	 *            if a non-transactional Session should be created when no
	 *            transactional Session can be found for the current thread
	 */
	public HibernateTemplateSpring(SessionFactory sessionFactory,
			boolean allowCreate) {
		super(sessionFactory, allowCreate);
	}

	/**
	 * 覆盖delete 实现 enity 中 只有主键也能删除
	 */
	public void delete(Object entity) throws DataAccessException {
		delete(entity, null);
	}

	/**
	 * 覆盖delete 实现 enity 中 只有主键也能删除
	 */
	public void delete(final Object entity, final LockMode lockMode)
			throws DataAccessException {
		execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				checkWriteOperationAllowed(session);
				if (lockMode != null) {
					session.lock(entity, lockMode);
				}
				ClassMetadata classMeta = session.getSessionFactory()
						.getClassMetadata(entity.getClass());
				HibernateAssert.fillValueObject(entity, classMeta);
				session.delete(entity);
				return null;
			}
		}, true);
	}

	/**
	 * 覆盖deleteAll 实现 enity 中 只有主键也能删除
	 */
	public void deleteAll(final Collection entities) throws DataAccessException {
		execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				checkWriteOperationAllowed(session);
				ClassMetadata classMeta = null;
				for (Iterator it = entities.iterator(); it.hasNext();) {
					Object entity = it.next();
					if (classMeta == null) {
						classMeta = session.getSessionFactory()
								.getClassMetadata(entity.getClass());
					}

					HibernateAssert.fillValueObject(entity, classMeta);
					session.delete(entity);
				}
				return null;
			}
		}, true);
	}

}
